import React, {FC, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from "react";
import "./css/FormPage.less";
import BaseForm from "../../module/form/BaseForm";
import useStateRef from "../../customUse/useStateRef";
import {createParams, tryFunction, tryFunctionAsync} from "../../utils";
import {Button, Spin} from "antd";
import {AxiosGet, AxiosSer} from "../../services/HttpService";
import GlobalBtn from "../../global/GlobalBtn.tsx";
import {getFormView, getVirtuallyView} from "../../services/ViewService.tsx";
import {useTranslation} from "react-i18next";
import GlobalIcon from "../../global/GlobalIcon.tsx";
import Config from "../../Config.tsx";
import {loadMenuChild} from "../../services/MenuService.tsx";
import {coreDispatch} from "../../utils/StoreUtil.tsx";

/*
* 公共表单
* */
interface FormPageProps {
    init?: any,
    row: any,
    getUrl: string,
    url: string,
    method: string,
    extend?: any,
    view: string,
    menuId: string,
    menu: any,
    labelWidth: any,
    formItemLayout: number,
    getInitData?: Function,
    loadView?: Function,
    beforeSubmit?: Function,
    onValuesChange?: Function
    formatFormView?: Function
    otherDs?: Object
}

const FormPage: FC<FormPageProps> = (props) => {
    const {otherDs = {}}: { otherDs?: any } = props;
    const {t} = useTranslation();

    const fromRef = useRef();
    const viewRef = useRef([]);
    const linkageRef = useRef({});

    const dataSource: any = {
        row: props.row || {},
        editForm: () => {
            setIsDisabledForm(false)
        },
        ...otherDs
    };

    const [editData, setEditData] = useState<any>({}),
        [menus, setMenus] = useState<any[]>([]),
        [view, setView] = useStateRef([], viewRef),
        [isDisabledForm, setIsDisabledForm] = useState<boolean>(true);

    const onValuesChange: Function = useCallback(async (changedValues: any, allValues: any) => {
        await tryFunctionAsync(async () => {
            linkageRef.current.valueChangeFormatView && (await linkageRef.current.valueChangeFormatView.call(null, allValues, fromRef.current.updateView));
        })
        props.onValuesChange && props.onValuesChange(changedValues, allValues, fromRef.current.updateView);
    }, [props.onValuesChange]);

    const loadView: Function = useCallback(async (editData: any) => {
        const {view, row = {}, objectModule}: { view: any, row: any, objectModule: string } = props;
        let result: any = {
            form: []
        };
        if (props.loadView) {
            result.form = await props.loadView(editData, dataSource);
            if (!result) {
                return false;
            }
        } else if (view) {
            result = await getFormView(view, editData, dataSource);
            tryFunction(() => {
                eval("window.linkageForm =" + result.linkageControl)
                linkageRef.current = window.linkageForm || {};
            });
            if (result.form && linkageRef.current.beforeFormatView) {
                await tryFunctionAsync(async () => {
                    result.form = (await linkageRef.current.beforeFormatView.call(null, result.form, editData)) || [];
                })
            }
        } else if (row.type && objectModule) {
            result = await getVirtuallyView(row.type, objectModule, editData, dataSource);
            tryFunction(() => {
                eval("window.linkageForm =" + result.linkageControl)
                linkageRef.current = window.linkageForm || {};
            });
            if (result.form && linkageRef.current.beforeFormatView) {
                await tryFunctionAsync(async () => {
                    result.form = (await linkageRef.current.beforeFormatView.call(null, result.form, editData)) || [];
                })
            }
        }

        if (result.form && props.formatFormView) {
            result.form = await props.formatFormView(result.form, editData);
        }
        setView(result.form);
    }, [props]);

    const getInitData: Function = useCallback(async () => {
        if (props.getInitData) {
            return props.getInitData(props.row)
        }
        let row: any = props.row;
        if (props.getUrl) {
            let newParams = createParams({id: props.row.id}, {flowData: [props.row], ...props, expandAttrKey: null})
            row = (await AxiosGet(props.getUrl, {...newParams, [Config.axiosSerMenuKey]: props.menuId})).data || {};
        }
        return row;
    }, [props.row, props.getInitData, props.getUrl, props.menuId]);

    const loadMenus: Function = useCallback(async () => {
        const {menuId} = props;
        if (menuId) {
            const data = await loadMenuChild({parentId: menuId, menuType: "BUTTON"});
            coreDispatch("menuReducer/createMenuBtn", data);
            setMenus(data);
        } else if (props.menu) {
            setMenus(props.menu);
        }
    }, [props.menuId]);

    const init: Function = useCallback(async () => {
        let editData = await getInitData();
        setEditData(editData);
        loadView(editData);
    }, [props.view, props.row, props.getInitData, props.menuId]);

    const beforeSubmit: Function = useCallback((params: any, view: any) => {
        if (props.beforeSubmit) {
            return props.beforeSubmit(params, view);
        }
        return params;
    }, [props.beforeSubmit]);

    const handleSave = useCallback(async () => {
        const values: any = await fromRef.current.validateFields();
        let params: any = await beforeSubmit(values, view);
        if (params === false) {
            return;
        }
        let {url, method = "PUT"}: { url: string, method: string } = props;
        let newParams = createParams(params, {flowData: [props.row], ...props});
        let result: any = await AxiosSer(url, method, {
            ...newParams,
            [Config.axiosSerMenuKey]: props.menuId
        }, true) || {};
        result.code === "1" && setIsDisabledForm(true);
    }, [props]);

    useEffect(() => {
        init();
    }, [props.view, props.getInitData]);

    useEffect(() => {
        loadMenus();
    }, [props.menuId]);

    useImperativeHandle(props.init, () => {
        return fromRef;
    });

    const renderBtn: any = useMemo(() => {
        if (!menus.length) {
            return null;
        }
        return (<GlobalBtn
            menus={menus}
            dataSource={dataSource}
        />);
    }, [menus]);

    const renderSaveBtn: any = useMemo(() => {
        return (<div className="sf_core_form_page_btn">
            <Button size="small" onClick={handleSave}
                    icon={<GlobalIcon size={14} name={"icon-save"}/>}>{t("save")}</Button>
            <Button size="small" onClick={() => (setIsDisabledForm(true))}
                    icon={<GlobalIcon size={14} name={"icon-close-page"}/>}>{t("cancel")}</Button>
        </div>)
    }, [])

    const renderEditForm = useMemo(() => {
        const {formItemLayout, labelWidth}: { formItemLayout: any, labelWidth: number } = props;
        if (!view || !view.length || !editData) {
            return <div style={{minHeight: 30}} className="spin-content"><Spin/></div>
        }
        return (
            <BaseForm
                init={fromRef}
                isDisabledForm={isDisabledForm}
                labelWidth={labelWidth}
                formItemLayout={formItemLayout}
                view={view}
                initValues={editData}
                onValuesChange={onValuesChange}
            />
        )
    }, [view, editData, isDisabledForm, props.formItemLayout, props.labelWidth])

    const renderFormPage = useMemo(() => {
        return (
            <div className={`sf_core_form_page ${menus.length ? '' : 'sf_core_form_page_only'}`}>
                {isDisabledForm ? renderBtn : renderSaveBtn}
                {renderEditForm}
            </div>
        )
    }, [menus, isDisabledForm, view, editData, props]);

    return (renderFormPage);
};

export default React.memo(FormPage);